﻿/*
 * *******************************************************
 *
 * 作者：hzy
 *
 * 开源地址：https://gitee.com/hzy6
 *
 * *******************************************************
 */

namespace HZY.Framework.Repository.EntityFramework.Repositories.Impl;

/// <summary>
/// 基础仓储 查询 实现
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TDbContext"></typeparam>
public abstract class QueryRepositoryImpl<T, TDbContext> : RepositoryCoreImpl<T, TDbContext>, IQueryRepository<T>
    where T : class, new()
    where TDbContext : DbContext
{
    /// <summary>
    /// 服务提供者
    /// </summary>
    protected readonly IServiceProvider ServiceProvider;

    /// <summary>
    /// 基础仓储 查询 实现
    /// </summary>
    /// <param name="dbContext"></param>
    /// <param name="serviceProvider"></param>
    /// <param name="filter"></param>
    protected QueryRepositoryImpl(TDbContext dbContext, IServiceProvider serviceProvider,
        Expression<Func<T, bool>>? filter = null)
        : base(dbContext, filter)
    {
        ServiceProvider = serviceProvider;
    }

    ///// <summary>
    ///// 资源释放
    ///// </summary>
    //protected override void DisposeAll()
    //{
    //    if (_databaseSchema != null)
    //    {
    //        _databaseSchema.Dispose();
    //    }

    //    base.DisposeAll();
    //}

    ///// <summary>
    ///// 资源释放
    ///// </summary>
    //protected override async Task DisposeAllAsync()
    //{
    //    if (_databaseSchema != null)
    //    {
    //        await _databaseSchema.DisposeAsync();
    //    }

    //    await base.DisposeAllAsync();
    //}

    #region 过滤

    /// <summary>
    /// 添加检索过滤
    /// </summary>
    /// <param name="filter"></param>
    /// <returns></returns>
    public virtual IQueryRepository<T> AddQueryFilter(Expression<Func<T, bool>>? filter = null)
    {
        Filter = filter;
        return this;
    }

    /// <summary>
    /// 忽略查询过滤条件
    /// </summary>
    /// <returns></returns>
    public virtual IQueryRepository<T> IgnoreQueryFilter()
    {
        IsIgnoreQueryFilter = true;
        return this;
    }

    /// <summary>
    /// 恢复忽略查询过滤条件
    /// </summary>
    /// <returns></returns>
    public virtual IQueryRepository<T> RecoveryQueryFilter()
    {
        IsIgnoreQueryFilter = false;
        return this;
    }

    #endregion

    #region 查询 复杂型

    /// <summary>
    /// 查询
    /// </summary>
    /// <param name="isTracking">是否追踪</param>
    /// <returns></returns>
    [Obsolete("请使用 GetAll 函数代替.")]
    public virtual IQueryable<T> Query(bool isTracking = true) => GetAll(isTracking);

    /// <summary>
    /// 查询 有跟踪
    /// </summary>
    public virtual IQueryable<T> Select => GetAll();

    /// <summary>
    /// 查询 无跟踪
    /// </summary>
    public virtual IQueryable<T> SelectNoTracking => GetAll(false);

    /// <summary>
    /// 查询
    /// </summary>
    /// <param name="isTracking"></param>
    /// <returns></returns>
    public virtual IQueryable<T> GetAll(bool isTracking = true)
    {
        return isTracking
            ? UnitOfWork.DbSet<T>().WhereIf(!IsIgnoreQueryFilter && Filter != null, Filter!).AsQueryable()
            : UnitOfWork.DbSet<T>().WhereIf(!IsIgnoreQueryFilter && Filter != null, Filter!).AsNoTracking();
    }

    #endregion

    #region 查询 单条

    /// <summary>
    /// 查询 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual T? Find(Expression<Func<T, bool>> expWhere)
        => Select.Where(expWhere).FirstOrDefault();

    /// <summary>
    /// 查询 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual T? Get(Expression<Func<T, bool>> expWhere)
        => Find(expWhere);

    /// <summary>
    /// 查询 根据id
    /// </summary>
    /// <param name="key"></param>
    /// <typeparam name="TKey"></typeparam>
    /// <returns></returns>
    public virtual T? FindById<TKey>(TKey key)
        => Select.FirstOrDefault(GetKeyEqualExpression(key));

    /// <summary>
    /// 查询 根据id
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <param name="key"></param>
    /// <returns></returns>
    public virtual T? GetById<TKey>(TKey key)
        => FindById(key);

    /// <summary>
    /// 查询 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual Task<T?> FindAsync(Expression<Func<T, bool>> expWhere)
        => Select.Where(expWhere).FirstOrDefaultAsync();

    /// <summary>
    /// 查询 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual Task<T?> GetAsync(Expression<Func<T, bool>> expWhere)
        => FindAsync(expWhere);

    /// <summary>
    /// 查询 根据id
    /// </summary>
    /// <param name="key"></param>
    /// <typeparam name="TKey"></typeparam>
    /// <returns></returns>
    public virtual Task<T?> FindByIdAsync<TKey>(TKey key)
        => Select.FirstOrDefaultAsync(GetKeyEqualExpression(key));

    /// <summary>
    /// 查询 根据id
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <param name="key"></param>
    /// <returns></returns>
    public virtual Task<T?> GetByIdAsync<TKey>(TKey key)
        => FindByIdAsync(key);

    #endregion

    #region 查询 多条

    /// <summary>
    /// 获取列表 根据查询条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual List<T> ToList(Expression<Func<T, bool>> expWhere)
        => Select.Where(expWhere).ToList();

    /// <summary>
    /// 获取列表 根据查询条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual List<T> GetAllList(Expression<Func<T, bool>> expWhere)
        => ToList(expWhere);

    /// <summary>
    /// 获取所有数据
    /// </summary>
    /// <returns></returns>
    public virtual List<T> ToListAll() => Select.ToList();

    /// <summary>
    /// 获取所有数据
    /// </summary>
    /// <returns></returns>
    public virtual List<T> GetAllList()
        => ToListAll();

    /// <summary>
    /// 获取列表 根据查询条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual Task<List<T>> ToListAsync(Expression<Func<T, bool>> expWhere)
        => Select.Where(expWhere).ToListAsync();

    /// <summary>
    /// 获取列表 根据查询条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual Task<List<T>> GetAllListAsync(Expression<Func<T, bool>> expWhere)
        => ToListAsync(expWhere);

    /// <summary>
    /// 获取所有数据
    /// </summary>
    /// <returns></returns>
    public virtual Task<List<T>> ToListAllAsync()
        => Select.ToListAsync();

    /// <summary>
    /// 获取所有数据
    /// </summary>
    /// <returns></returns>
    public virtual Task<List<T>> GetAllListAsync()
        => ToListAllAsync();

    #endregion

    #region 查询 多条 缓存

    /// <summary>
    /// 获取列表 根据查询条件 默认缓存 时间：20分钟
    /// </summary>
    /// <returns></returns>
    public List<T> GetAllListByCache(int minute = 20)
    {
        var memoryCache = ServiceProvider.GetService<IMemoryCache>();
        if (memoryCache is null)
        {
            throw new Exception("未找到缓存服务");
        }

        var key = $"Repository_{typeof(T).Name}_{nameof(GetAllListByCache)}";

        return memoryCache.GetOrCreate(key, opt =>
        {
            opt.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(minute);
            return GetAllList();
        }) ?? [];
    }

    #endregion

    #region 是否存在 、 数量

    /// <summary>
    /// 获取数量
    /// </summary>
    /// <returns></returns>
    public virtual int Count()
        => Select.Count();

    /// <summary>
    /// 获取数量
    /// </summary>
    /// <returns></returns>
    public virtual long CountLong()
        => Select.LongCount();

    /// <summary>
    /// 获取数量 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual int Count(Expression<Func<T, bool>> expWhere)
        => Select.Count(expWhere);

    /// <summary>
    /// 获取数量 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual long CountLong(Expression<Func<T, bool>> expWhere)
        => Select.LongCount(expWhere);

    /// <summary>
    /// 是否存在 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual bool Any(Expression<Func<T, bool>> expWhere)
        => Select.Any(expWhere);

    /// <summary>
    /// 获取数量
    /// </summary>
    /// <returns></returns>
    public virtual Task<int> CountAsync()
        => Select.CountAsync();

    /// <summary>
    /// 获取数量
    /// </summary>
    /// <returns></returns>
    public virtual Task<long> CountLongAsync()
        => Select.LongCountAsync();

    /// <summary>
    /// 获取数量 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual Task<int> CountAsync(Expression<Func<T, bool>> expWhere)
        => Select.CountAsync(expWhere);

    /// <summary>
    /// 获取数量 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual Task<long> CountLongAsync(Expression<Func<T, bool>> expWhere)
        => Select.LongCountAsync(expWhere);

    /// <summary>
    /// 是否存在 根据条件
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual Task<bool> AnyAsync(Expression<Func<T, bool>> expWhere)
        => Select.AnyAsync(expWhere);

    #endregion

    #region 原生 sql 操作

    /// <summary>
    /// 查询根据sql语句
    /// EFCore 原生sql查询
    /// </summary>
    /// <returns> IQueryable </returns>
    public virtual IQueryable<T> QueryableBySql(string sql, params object[] parameters)
    {
        return UnitOfWork.DbSet<T>().FromSqlRaw(sql, parameters);
    }

    /// <summary>
    /// 根据 sql 查询表格
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="parameters"></param>
    /// <returns></returns>
    public virtual DataTable? QueryDataTableBySql(string sql, params object[] parameters)
    {
        return Context.Database.QueryDataTableBySql(sql, parameters);
    }

    /// <summary>
    /// 根据 sql 查询表格
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="parameters"></param>
    /// <returns></returns>
    public virtual Task<DataTable?> QueryDataTableBySqlAsync(string sql, params object[] parameters)
    {
        return Context.Database.QueryDataTableBySqlAsync(sql, parameters);
    }

    /// <summary>
    /// 根据 sql 查询字典集合
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="parameters"></param>
    /// <returns></returns>
    public virtual List<Dictionary<string, object?>>? QueryDicBySql(string sql, params object[] parameters)
    {
        return Context.Database.QueryDicBySql(sql, parameters);
    }

    /// <summary>
    /// 根据 sql 查询字典集合
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="parameters"></param>
    /// <returns></returns>
    public virtual Task<List<Dictionary<string, object?>>?> QueryDicBySqlAsync(string sql, params object[] parameters)
    {
        return Context.Database.QueryDicBySqlAsync(sql, parameters);
    }

    /// <summary>
    /// 查询根据sql语句
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="parameters"></param>
    /// <returns></returns>
    public virtual List<T>? QueryBySql(string sql, params object[] parameters)
    {
        return Context.Database.QueryBySql<T>(sql, parameters);
    }

    /// <summary>
    /// 查询根据sql语句
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="parameters"></param>
    /// <returns></returns>
    public virtual Task<List<T>?> QueryBySqlAsync(string sql, params object[] parameters)
    {
        return Context.Database.QueryBySqlAsync<T>(sql, parameters);
    }

    /// <summary>
    /// 查询根据sql返回单个值
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="parameters"></param>
    /// <returns></returns>
    public virtual object? QuerySingleBySql(string sql, params object[] parameters)
    {
        return Context.Database.QuerySingleBySql(sql, parameters);
    }

    /// <summary>
    /// 查询根据sql返回单个值
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="parameters"></param>
    /// <returns></returns>
    public virtual Task<object?> QuerySingleBySqlAsync(string sql, params object[] parameters)
    {
        return Context.Database.QuerySingleBySqlAsync(sql, parameters);
    }

    /// <summary>
    /// 查询根据sql返回单个值
    /// </summary>
    /// <typeparam name="TResult"></typeparam>
    /// <param name="sql"></param>
    /// <param name="parameters"></param>
    /// <returns></returns>
    public virtual TResult QuerySingleBySql<TResult>(string sql, params object[] parameters)
        where TResult : struct
    {
        return Context.Database.QuerySingleBySql<TResult>(sql, parameters);
    }

    /// <summary>
    /// 查询根据sql返回单个值
    /// </summary>
    /// <typeparam name="TResult"></typeparam>
    /// <param name="sql"></param>
    /// <param name="parameters"></param>
    /// <returns></returns>
    public virtual Task<TResult> QuerySingleBySqlAsync<TResult>(string sql, params object[] parameters)
        where TResult : struct
    {
        return Context.Database.QuerySingleBySqlAsync<TResult>(sql, parameters);
    }

    #endregion

    #region 字典信息

    /// <summary>
    /// 获取字典集合
    /// </summary>
    /// <returns></returns>
    public List<Dictionary<string, object?>> GetDictListByDict<TEntity>(List<TEntity> list)
        where TEntity : class, new()
    {
        if (list.Count == 0)
        {
            return [];
        }

        var dataDictionaryMappingIntercept = ActivatorUtilities.CreateInstance(ServiceProvider,
            RepositoryEntityFrameworkExtensions
                .DataDictionaryMappingInterceptType) as IDataDictionaryMappingIntercept; // di 创建服务

        if (dataDictionaryMappingIntercept is null)
        {
            throw new NotImplementedException("jobTaskObject is null");
        }

        // 通过实体 ，扫描
        var modelType = typeof(T);
        var dictList = new List<DictInfo>();

        var propertyInfoList = modelType.GetProperties();
        foreach (var propertyInfo in propertyInfoList)
        {
            // 获取自定义特性
            var dictAttribute = propertyInfo.GetCustomAttribute<DictAttribute>();
            if (dictAttribute is null)
            {
                continue;
            }

            // 组装字典信息
            var dictInfo = new DictInfo(dictAttribute, propertyInfo.Name);
            dictList.Add(dictInfo);
        }

        // 开始准备数据
        foreach (var item in list)
        {
            var type = item.GetType();
            foreach (var property in type.GetProperties())
            {
                var dict = dictList.FirstOrDefault(w => w.FieldName == property.Name);
                if (dict is null)
                {
                    continue;
                }

                var value = property.GetValue(item);
                if (value is null)
                {
                    continue;
                }

                dict.Data[value] = null;
            }
        }

        // 查询数据
        foreach (var dictInfo in dictList)
        {
            dataDictionaryMappingIntercept.HandlerData(dictInfo, this.UnitOfWork);
        }

        // 组装字典数据
        var result = new List<Dictionary<string, object?>>();
        foreach (var item in list)
        {
            var data = new Dictionary<string, object?>();

            var type = item.GetType();
            foreach (var property in type.GetProperties())
            {
                var key = property.Name;
                var value = property.GetValue(item);
                if (!data!.ContainsKey(key))
                {
                    data[key] = value;
                }

                //
                var dict = dictList.FirstOrDefault(w => w.FieldName == key);
                if (dict is null)
                {
                    continue;
                }

                // 如果设置了 ToField 那么直接对这个字段作为key
                var keyName = string.IsNullOrWhiteSpace(dict.DictAttribute.ToField)
                    ? key + "_dictText"
                    : dict.DictAttribute.ToField;
                // 通过数据源获取数据
                if (value is null)
                {
                    data[keyName] = null;
                }
                else
                {
                    dict.Data.TryGetValue(value, out var textValue);
                    data[keyName] = textValue;
                }
            }

            // 添加到结果集
            result.Add(data);
        }

        return result;
    }

    /// <summary>
    /// 获取字典集合
    /// </summary>
    /// <returns></returns>
    public Dictionary<string, object?> GetDictByDict<TEntity>(TEntity input)
        where TEntity : class, new()
    {
        var dataDictionaryMappingIntercept = ActivatorUtilities.CreateInstance(ServiceProvider,
            RepositoryEntityFrameworkExtensions
                .DataDictionaryMappingInterceptType) as IDataDictionaryMappingIntercept; // di 创建服务

        if (dataDictionaryMappingIntercept is null)
        {
            throw new NotImplementedException("jobTaskObject is null");
        }

        // 通过实体 ，扫描
        var modelType = input.GetType();
        var dictList = new List<DictInfo>();

        var propertyInfoList = modelType.GetProperties();
        foreach (var propertyInfo in propertyInfoList)
        {
            // 获取自定义特性
            var dictAttribute = propertyInfo.GetCustomAttribute<DictAttribute>();
            if (dictAttribute is null)
            {
                continue;
            }

            // 组装字典信息
            var dictInfo = new DictInfo(dictAttribute, propertyInfo.Name);
            dictList.Add(dictInfo);
        }

        // 开始准备数据
        foreach (var property in modelType.GetProperties())
        {
            var dict = dictList.FirstOrDefault(w => w.FieldName == property.Name);
            if (dict is null)
            {
                continue;
            }

            var value = property.GetValue(input);
            if (value is null)
            {
                continue;
            }

            dict.Data[value] = null;
        }

        // 查询数据
        foreach (var dictInfo in dictList)
        {
            dataDictionaryMappingIntercept.HandlerData(dictInfo, this.UnitOfWork);
        }

        // 组装字典数据
        var result = new Dictionary<string, object?>();
        foreach (var property in modelType.GetProperties())
        {
            var key = property.Name;
            var value = property.GetValue(input);
            if (!result!.ContainsKey(key))
            {
                result[key] = value;
            }

            //
            var dict = dictList.FirstOrDefault(w => w.FieldName == key);
            if (dict is null)
            {
                continue;
            }

            // 如果设置了 ToField 那么直接对这个字段作为key
            var keyName = string.IsNullOrWhiteSpace(dict.DictAttribute.ToField)
                ? key + "_dictText"
                : dict.DictAttribute.ToField;
            // 通过数据源获取数据
            if (value is null)
            {
                result[keyName] = null;
            }
            else
            {
                dict.Data.TryGetValue(value, out var textValue);
                result[keyName] = textValue;
            }
        }

        return result;
    }

    #endregion

    #region 对象映射

    /// <summary>
    /// 获取字典集合
    /// </summary>
    /// <returns></returns>
    public List<TEntity> GetListByDict<TEntity>(List<TEntity> list)
        where TEntity : class, new()
    {
        if (list.Count == 0)
        {
            return [];
        }

        var dataDictionaryMappingIntercept = ActivatorUtilities.CreateInstance(ServiceProvider,
            RepositoryEntityFrameworkExtensions
                .DataDictionaryMappingInterceptType) as IDataDictionaryMappingIntercept; // di 创建服务

        if (dataDictionaryMappingIntercept is null)
        {
            throw new NotImplementedException("jobTaskObject is null");
        }

        // 通过实体 ，扫描
        var modelType = typeof(T);
        var dictList = new List<DictInfo>();

        var propertyInfoList = modelType.GetProperties();
        foreach (var propertyInfo in propertyInfoList)
        {
            // 获取自定义特性
            var dictAttribute = propertyInfo.GetCustomAttribute<DictAttribute>();
            if (dictAttribute is null)
            {
                continue;
            }

            // 组装字典信息
            var dictInfo = new DictInfo(dictAttribute, propertyInfo.Name);
            dictList.Add(dictInfo);
        }

        // 开始准备数据
        foreach (var item in list)
        {
            var type = item.GetType();
            foreach (var property in type.GetProperties())
            {
                var dict = dictList.FirstOrDefault(w => w.FieldName == property.Name);
                if (dict is null)
                {
                    continue;
                }

                var value = property.GetValue(item);
                if (value is null)
                {
                    continue;
                }

                dict.Data[value] = null;
            }
        }

        // 查询数据
        foreach (var dictInfo in dictList)
        {
            dataDictionaryMappingIntercept.HandlerData(dictInfo, this.UnitOfWork);
        }

        // 组装字典数据
        foreach (var item in list)
        {
            var type = item.GetType();
            foreach (var property in type.GetProperties())
            {
                var key = property.Name;
                var value = property.GetValue(item);
                //
                var dict = dictList.FirstOrDefault(w => w.FieldName == key);
                if (dict is null)
                {
                    continue;
                }

                // 如果设置了 ToField 那么直接对这个字段作为key
                var keyName = dict.DictAttribute.ToField;
                if (!string.IsNullOrWhiteSpace(keyName) && value is not null)
                {
                    dict.Data.TryGetValue(value, out var textValue);
                    type.GetProperty(keyName)?.SetValue(item, textValue);
                }
            }
        }

        return list;
    }

    /// <summary>
    /// 获取字典集合
    /// </summary>
    /// <returns></returns>
    public TEntity GetByDict<TEntity>(TEntity input) where TEntity : class, new()
    {
        var dataDictionaryMappingIntercept = ActivatorUtilities.CreateInstance(ServiceProvider,
            RepositoryEntityFrameworkExtensions
                .DataDictionaryMappingInterceptType) as IDataDictionaryMappingIntercept; // di 创建服务

        if (dataDictionaryMappingIntercept is null)
        {
            throw new NotImplementedException("jobTaskObject is null");
        }

        // 通过实体 ，扫描
        var modelType = input.GetType();
        var dictList = new List<DictInfo>();

        var propertyInfoList = modelType.GetProperties();
        foreach (var propertyInfo in propertyInfoList)
        {
            // 获取自定义特性
            var dictAttribute = propertyInfo.GetCustomAttribute<DictAttribute>();
            if (dictAttribute is null)
            {
                continue;
            }

            // 组装字典信息
            var dictInfo = new DictInfo(dictAttribute, propertyInfo.Name);
            dictList.Add(dictInfo);
        }

        // 开始准备数据
        foreach (var property in modelType.GetProperties())
        {
            var dict = dictList.FirstOrDefault(w => w.FieldName == property.Name);
            if (dict is null)
            {
                continue;
            }

            var value = property.GetValue(input);
            if (value is null)
            {
                continue;
            }

            dict.Data[value] = null;
        }

        // 查询数据
        foreach (var dictInfo in dictList)
        {
            dataDictionaryMappingIntercept.HandlerData(dictInfo, this.UnitOfWork);
        }

        // 组装字典数据
        foreach (var property in modelType.GetProperties())
        {
            var key = property.Name;
            var value = property.GetValue(input);
            //
            var dict = dictList.FirstOrDefault(w => w.FieldName == key);
            if (dict is null)
            {
                continue;
            }

            // 如果设置了 ToField 那么直接对这个字段作为key
            var keyName = dict.DictAttribute.ToField;
            if (!string.IsNullOrWhiteSpace(keyName) && value is not null)
            {
                dict.Data.TryGetValue(value, out var textValue);
                modelType.GetProperty(keyName)?.SetValue(input, textValue);
            }
        }

        return input;
    }

    #endregion
}